package com.lyn.pluginhost.plugin

import android.annotation.SuppressLint
import android.app.Application
import android.content.Intent
import android.content.pm.PackageManager.GET_META_DATA
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.util.Log
import com.lyn.io.file.Folder
import com.lyn.io.file.FolderFactory
import com.lyn.pluginapi.entity.PluginInfo
import com.lyn.pluginapi.factory.ClassLoaderFactory
import com.lyn.pluginapi.factory.ResourcesFactory
import com.lyn.pluginapi.jump.JumpHelper
import com.lyn.pluginhost.activity.ProxyPluginActivity
import com.lyn.pluginhost.activity.ProxyPluginActivityStack
import com.lyn.pluginhost.other.CreateResourceBloc
import com.lyn.pluginhost.other.SoOperate
import dalvik.system.DexClassLoader
import java.io.ByteArrayOutputStream
import java.io.File

/**
 * 插件Host宿主
 * @author longyn 2025/07/04
 * @version 1.0.0
 */
internal class PluginManager {

    companion object {
        const val TAG = "PluginManager"
        val instance by lazy { PluginManager() }

        //插件存放根目录
        const val PLUGIN_ROOT_FOLDER_NAME = "pluginRoot"

        //插件so文件存放根目录
        const val PLUGIN_SO_ROOT_FOLDER_NAME = "pluginSoRoot"
    }

    private lateinit var application: Application
    private lateinit var pluginRootFolder: Folder
    private lateinit var pluginRootSoFolder: Folder


    /**
     * 初始化
     * @param application
     */
    fun initialize(application: Application): Boolean {
        Log.d(TAG, "initialize")
        if (this@PluginManager::application.isInitialized) {
            return true
        }
        try {
            this.application = application
            pluginRootFolder =
                FolderFactory.create(
                    PLUGIN_ROOT_FOLDER_NAME,
                    application.filesDir.absolutePath,
                    isCreate = true
                )
            pluginRootSoFolder =
                FolderFactory.create(
                    PLUGIN_SO_ROOT_FOLDER_NAME,
                    application.filesDir.absolutePath,
                    isCreate = true
                )
            return true
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return false
    }

    /**
     * 加载插件
     * @param path 插件文件路径
     * @return PluginInfo 插件信息
     */
    suspend fun loadPlugin(path: String): PluginInfo? {
        try {
            val file = File(path)
            if (file.exists()) {
                file.setWritable(false)
            }
            var librarySearchPath = ""
            var classLoader = DexClassLoader(
                path,
                application.cacheDir.absolutePath,
                librarySearchPath,
                null
            )
            val resources = CreateResourceBloc.create(path, application)
            val pluginConfigClass = classLoader.loadClass("com.lyn.pluginapi.PluginConfig")
            val pluginIdField = pluginConfigClass.getDeclaredField("PLUGIN_ID")
            val pluginNameField = pluginConfigClass.getDeclaredField("PLUGIN_NAME")
            val pluginLauncherClassNameField =
                pluginConfigClass.getDeclaredField("PLUGIN_LAUNCHER_CLASS_NAME")
            val pluginVersionField = pluginConfigClass.getDeclaredField("PLUGIN_VERSION")
            val pluginId = pluginIdField.get(null) as String
            val pluginName = pluginNameField.get(null) as String
            val pluginLauncherClassName = pluginLauncherClassNameField.get(null) as String
            val pluginVersion = pluginVersionField.get(null) as Int
            val pluginInfo = PluginInfo(
                pluginId,
                pluginName,
                pluginLauncherClassName,
                pluginVersion,
                path
            )
            val folder = FolderFactory.create(pluginId, pluginRootSoFolder.getRootPath())
            SoOperate.extractPluginSoToTargetFolder(path, folder)
            librarySearchPath = folder.getRootPath()
            classLoader = DexClassLoader(
                path,
                application.cacheDir.absolutePath,
                librarySearchPath,
                application.classLoader
            )
            ResourcesFactory.create(pluginId, resources)
            ClassLoaderFactory.create(pluginId, classLoader)
            return pluginInfo
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return null
    }

    suspend fun getPluginLogo(pluginId: String, path: String): ByteArray {
        val packageInfo =
            application.packageManager.getPackageArchiveInfo(path, GET_META_DATA)
        val icon = packageInfo?.applicationInfo?.icon ?: 0
        ResourcesFactory.get(pluginId)?.let {
            @SuppressLint("UseCompatLoadingForDrawables")
            val drawable = it.getDrawable(icon, it.newTheme())
            val bitmap = Bitmap.createBitmap(
                drawable.intrinsicWidth,
                drawable.intrinsicHeight,
                Bitmap.Config.ARGB_8888
            )
            val canvas = Canvas(bitmap)
            canvas.drawColor(Color.TRANSPARENT)
            drawable.setBounds(0, 0, canvas.width, canvas.height)
            drawable.draw(canvas)
            val byteArrayOutputStream = ByteArrayOutputStream()
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream)
            val bytes = byteArrayOutputStream.toByteArray()
            byteArrayOutputStream.close()
            return bytes
        }
        return byteArrayOf()
    }


    /**
     * 加载全部插件
     * @return 插件list
     */
    suspend fun loadAllPlugin(): MutableList<PluginInfo> {
        val pluginInfoList: MutableList<PluginInfo> = mutableListOf()
        pluginRootFolder.getAllFileName().forEach { fileName ->
            val file = pluginRootFolder.getFile(fileName)
            if (file.isFile()) {
                val path = file.absolutePath
                loadPlugin(path)?.let { pluginInfo ->
                    pluginInfoList.add(pluginInfo)
                }
            }
        }
        return pluginInfoList
    }

    /**
     * 删除插件
     * @param pluginInfo 插件信息
     */
    fun removePlugin(pluginInfo: PluginInfo) {
        ClassLoaderFactory.remove(pluginInfo.id)
        ResourcesFactory.remove(pluginInfo.id)
        val file = File(pluginInfo.path)
        if (file.exists()) {
            file.delete()
        }
        pluginRootSoFolder.deleteFile(pluginInfo.id)
        val cacheFile = File(application.cacheDir, file.name)
        if (cacheFile.exists()) {
            cacheFile.delete()
        }
    }


    /**
     * 打开插件
     */
    fun openPlugin(pluginId: String, className: String): Boolean {
        try {
            JumpHelper.instance.springboardPluginId = pluginId
            JumpHelper.instance.springboardPluginClassName = className
            val intent = Intent(application, ProxyPluginActivity::class.java)
            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            application.startActivity(intent)
            return true
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return false
    }

    /**
     * 关闭插件
     */
    fun closePlugin(pluginId: String) {
        ProxyPluginActivityStack.instance.close(pluginId)
    }
}